// +FHDR------------------------------------------------------------
//                 Copyright (c) 2022 .
//                       ALL RIGHTS RESERVED
// -----------------------------------------------------------------
// Filename      : cpu_monitor.sv
// Author        : 
// Created On    : 2022-08-25 15:47
// Last Modified : 
// -----------------------------------------------------------------
// Description:
//
//
// -FHDR------------------------------------------------------------

`ifndef __CPU_MONITOR_SV__
`define __CPU_MONITOR_SV__

class cpu_monitor extends uvm_monitor;
	virtual cpu_interface vif;
	uvm_analysis_port #(cpu_transaction) ap;
	
	`uvm_component_utils(cpu_monitor)
	
	extern function new(string name = "cpu_monitor", uvm_component parent=null);
	extern virtual function void build_phase(uvm_phase phase);
	extern virtual task run_phase(uvm_phase phase);
	extern virtual task receive_pkt();
endclass: cpu_monitor

function cpu_monitor::new(string name = "cpu_monitor", uvm_component parent=null);
	super.new(name, parent);
endfunction: new

function void cpu_monitor::build_phase(uvm_phase phase);
	super.build_phase(phase);
	`uvm_info("cpu_monitor", "build_phase is called", UVM_HIGH);
	if(!uvm_config_db #(virtual cpu_interface)::get(this, "", "vif", vif))begin
		`uvm_fatal("cpu_monitor", "virtual interface get fatal");
	end
	ap   = new("ap", this);
endfunction: build_phase

task cpu_monitor::run_phase(uvm_phase phase);
    while(!this.vif.rst_n) @this.vif.mon;
	fork 
		this.receive_pkt();
	join_none
endtask: run_phase

task cpu_monitor::receive_pkt();
	cpu_transaction data = new();
	while(1) begin
		@this.vif.mon;
		if(this.vif.mon.CPU_CS_N === 1'b0 & this.vif.mon.CPU_WE_N === 1'b0 && this.vif.mon.CPU_RDY_N === 1'b0 && this.vif.mon.CPU_RDY_N_ff === 1'b1)begin
            data.CPU_ADDR = this.vif.mon.CPU_ADDR;
            data.CPU_DATA = this.vif.mon.CPU_WDATA;
            data.CPU_RW_TYPE = 1'b1;
            data.unpack();
			ap.write(data);
		end
        else if(this.vif.mon.CPU_CS_N === 1'b0 & this.vif.mon.CPU_RD_N === 1'b0 && this.vif.mon.CPU_RDY_N === 1'b0 && this.vif.mon.CPU_RDY_N_ff === 1'b1)begin
            data.CPU_ADDR = this.vif.mon.CPU_ADDR;
            data.CPU_DATA = this.vif.mon.CPU_RDATA;
            data.CPU_RW_TYPE = 1'b0;
            data.unpack();
			ap.write(data);
		end
	end
endtask: receive_pkt

`endif
